#ifndef BLEEDTHROUGHTRINARISATION_HPP
#define BLEEDTHROUGHTRINARISATION_HPP

/** @todo remove unassesary includes */
#include <assert.h>
#include <iostream>
#include <memory>

#include <girlTools/girlToolsImage.hpp>
#include <girl/girlToger.hpp>

#include "Exceptions.hpp"

/**
  * This class is used to trinarize a recto image and needs the verso image
  *
  */
class BleedThroughTrinarisation
{
private:
    /**
      * @throws Exceptions::NotSameSizeZxceptions
      *
      */
    BleedThroughTrinarisation(const girl::tools::Image &recto,const  girl::tools::Image &verso);
    ~BleedThroughTrinarisation();

public:

    /**
      * return the recto image trinarized
      * Red = bleedThrough
      * Black = Ink
      * White = Background
      */
    virtual girl::tools::Image  trinarized();


    /**
      * This class can only be changed if we change recto.
      */
    static BleedThroughTrinarisation * reset(const girl::tools::Image &recto,
               const girl::tools::Image &verso);
    /**
      * Also Singleton
      * @todo Templatiser
      */
    static BleedThroughTrinarisation * instance();

    static void kill();


    /**
      * The bleedthrough toger.
      */
    virtual inline const girl::toger & bleedthroughToger() const
    {
        std::cout << "hello " << std::endl;
        return _bleedThroughToger;
    }
    /**
      * The background toger.
      */
    virtual inline const girl::toger & backgroundToger() const
    {return _backgroundToger;}
    /**
      * The ink toger.
      */
    virtual inline const girl::toger & inkToger() const
    {return _inkToger;}

protected :
        virtual float getRectoBackgroundThreshold(int rectoInkThd) const;
        virtual float getVersoBackgroundThreshold() const;
        virtual float getRectoInkThreshold() const;

private :
        float getBackGroundThreshold(const girl::tools::Image &image) const;
        void applyMedianFilter(girl::tools::Image &image);
        void colorize(const girl::toger &tog, const girl::tools::Pixel &coul);

public :
        static const girl::tools::Pixel BLEED_THROUGH;
        static const girl::tools::Pixel INK;
        static const girl::tools::Pixel BACKGROUND;

private :
        girl::toger _bleedThroughToger;
        girl::toger _backgroundToger;
        girl::toger _inkToger;

        girl::tools::Image _trinarized;

        const girl::tools::Image &_recto;
        const girl::tools::Image &_verso;

        static BleedThroughTrinarisation * _instance;
        static const girl::tools::Image *rectoPtr;
};




class ConditionOnRectoAndVersoSameRegion : public girl::toger::sameRegion
{

public :
    ConditionOnRectoAndVersoSameRegion():
        _recto(girl::tools::Image()),_verso(girl::tools::Image()){}
    ConditionOnRectoAndVersoSameRegion(const girl::tools::Image &recto, const girl::tools::Image &verso);
    virtual ~ConditionOnRectoAndVersoSameRegion(){}

    bool same(const girl::point &p, girl::direction dir);

protected:
    virtual bool condition(int x, int y) = 0;

protected :
        const girl::tools::Image &_recto;
        const girl::tools::Image &_verso;

};

class BleedThroughSameRegion : public ConditionOnRectoAndVersoSameRegion
{
public:


    BleedThroughSameRegion(const girl::tools::Image &recto, const girl::tools::Image &verso,
                           float rectoBackThd, float rectoInkThd, float versoBackThd);

    virtual ~BleedThroughSameRegion(){}



protected:
    virtual bool estTransparence(int i, int j);
    virtual bool condition(int x, int y)
    {return estTransparence(x,y);}


protected :
    float _rectoBackThd,  _rectoInkThd,  _versoBackThd;
};

class InkSameRegion : public BleedThroughSameRegion
{
public:

    InkSameRegion(const girl::tools::Image &recto, const girl::tools::Image &verso,
                         float rectoBackThd, float rectoInkThd, float versoBackThd)
                             : BleedThroughSameRegion(recto,verso,rectoBackThd,rectoInkThd,versoBackThd)
    {}

    virtual ~InkSameRegion(){}



protected:
    virtual bool condition(int x, int y);

};


class BackgroundSameRegion : public BleedThroughSameRegion
{
public :
    BackgroundSameRegion(const girl::tools::Image &recto, const girl::tools::Image &verso,
                         float rectoBackThd, float rectoInkThd, float versoBackThd)
                             : BleedThroughSameRegion(recto,verso,rectoBackThd,rectoInkThd,versoBackThd)
    {}
    virtual ~BackgroundSameRegion(){};

protected :
        virtual bool condition(int x, int y);

};




#endif // BLEEDTHROUGHTRINARISATION_HPP
